package com.sixi.GeoTransfer;

import java.awt.geom.Point2D;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.sixi.GeoTransfer.model.AreaModel;
import com.sixi.GeoTransfer.model.City;
import com.sixi.GeoTransfer.model.Country;

/**
 * Hello world!
 *
 */
public class App {
	
	public static List<AreaModel> cityInfoList;
	
	public static void main(String[] args) {
		System.out.println("Hello World!");
		
		// 存放城市经纬度信息
		Map<String, List<Point2D.Double>> map1 = new HashMap<String, List<Point2D.Double>>();
		File f = new File("C:\\Users\\Vincent\\Desktop\\longitude\\yunan_city.txt");
		File f2 = new File("C:\\Users\\Vincent\\Desktop\\longitude\\customer.csv");
		BufferedReader br = null;
		BufferedReader br2 = null;
		try {
			System.out.println("读取城市边界经纬度信息");
			cityInfoList = RatInCatUtils.loadCityInfo("./src/main/resources/yunnan_city_info.txt", "yunnan");
			
			
			br = new BufferedReader(new FileReader(f));
			String temp;
			while ((temp = br.readLine()) != null) {
				String[] urlsArray = temp.split("\\t");
				List<Point2D.Double> pts = new ArrayList<Point2D.Double>();
				for (String lola : urlsArray[7].split(";")) {
					String[] lolas = lola.split(",");
					if (lolas.length == 2) {
						Point2D.Double cityPt = new Point2D.Double(new Double(lolas[0]), new Double(lolas[1]));
						pts.add(cityPt);
					}
				}
				map1.put(urlsArray[6], pts);
			}

			
			
			System.out.println("判断并输出地址");

			FileOutputStream out = null;

			out = new FileOutputStream(new File("C:\\Users\\Vincent\\Desktop\\longitude\\locate_result.csv"));

			br2 = new BufferedReader(new FileReader(f2));
			String temp2;
			long time = 0l;
			int t = 0;
			while ((temp2 = br2.readLine()) != null) {
				String[] urlsArray = temp2.split(",");
				if (urlsArray.length == 3) {
					Point2D.Double cityPt = new Point2D.Double(new Double(urlsArray[1]), new Double(urlsArray[2]));
					
					AreaModel am = RatInCatUtils.ratInCatAreaModel(cityPt, cityInfoList);
					String citybuy = am.getName();
					boolean isInside = false;
					for (String city : map1.keySet()) {
						long beforeTime = System.currentTimeMillis();
						isInside = RatInCatUtils.isRatInCat(cityPt, map1.get(city)); // 判断是否坐落于该城市内
						long afterTime = System.currentTimeMillis();
						long perTime = afterTime - beforeTime;
						time += perTime;
						if (isInside) {

							String outPutStr = urlsArray[0] + "," + urlsArray[1] + "," + urlsArray[2] + "," + city + "," + citybuy + ","
									 + "\r\n";

							out.write(outPutStr.getBytes("utf-8"));
							System.out.println(
									"cityPt点(" + urlsArray[1] + "," + urlsArray[2] + ")位于---------------" + city + "," + citybuy);
							break;
						}
					}
					if(!isInside) {
						String outPutStr = urlsArray[0] + "," + urlsArray[1] + "," + urlsArray[2] + "," + "未包含" + "," + citybuy + ","
								 + "\r\n";

						out.write(outPutStr.getBytes("utf-8"));
						System.out.println(
								"cityPt点(" + urlsArray[1] + "," + urlsArray[2] + ")位于---------------" + "未包含" + "," + citybuy);
					}
				}
				t++;
			}
			out.write(("总耗时：" + "," + time + "," + "总处理数：" + "," + t + "," + "平均每条耗时：" + "," + new Double(time/t)).getBytes("utf-8") );
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 判断点是否在多边形内 ，假设多边形的点事按逆时针画圈。
	 * 
	 * @param point
	 *            检测点
	 * @param pts
	 *            多边形的顶点
	 * @return 点在多边形内返回true,否则返回false
	 */
	public static boolean IsPtInPoly(Point2D.Double point, List<Point2D.Double> pts) {

		int N = pts.size();
		boolean boundOrVertex = true; // 如果点位于多边形的顶点或边上，也算做点在多边形内，直接返回true
		int intersectCount = 0;// cross points count of x
		double precision = 2e-10; // 浮点类型计算时候与0比较时候的容差
		Point2D.Double p1, p2;// neighbour bound vertices
		Point2D.Double p = point; // 当前点

		p1 = pts.get(0);// left vertex
		for (int i = 1; i <= N; ++i) {// check all rays
			// 如果p是个端点，直接返回true
			if (p.equals(p1)) {
				return boundOrVertex;// p is an vertex
			}

			// 如果线段最小经度在p点的经度右边
			// 或者如果线段的最大经度在p点的经度左边
			// 那么肯定不会相交。跳过。将p2端点赋值给p1端点，接着计算下一端点++i。
			p2 = pts.get(i % N);// right vertex
			if (p.x < Math.min(p1.x, p2.x) || p.x > Math.max(p1.x, p2.x)) {// ray is outside of our interests
				p1 = p2;
				continue;// next ray left point
			}

			// 如果线段的最小经度在p点的左边
			// 并且如果线段的最大经度在p点的右边
			// 那么一定会与线段的非端点部分相交
			if (p.x > Math.min(p1.x, p2.x) && p.x < Math.max(p1.x, p2.x)) {// ray is crossing over by the algorithm
																			// (common part of)
				// 如果p点的纬度值小于等于线段的最大纬度值，则p点在线段的下方
				if (p.y <= Math.max(p1.y, p2.y)) {// x is before of ray
					// 如果线段为垂直线段
					// 并且p的纬度在线段上，则射线与线段平行，且穿过线段（不可能发生，因为没有点既大于线段的最小X值，又小于线段的最大X值，且最大最小值还相等。）
					if (p1.x == p2.x && p.y >= Math.min(p1.y, p2.y)) {// overlies on a horizontal ray
						return boundOrVertex;
					}
					// 如果线段是平行的，则射线与线段垂直
					if (p1.y == p2.y) {// ray is vertical
						// 如果p点在线段上，则表示点在多边形内
						if (p1.y == p.y) {// overlies on a vertical ray
							return boundOrVertex;
						} else {// before ray
								// 如果不在线段上，则记录一次相交
							++intersectCount;
						}
					} else {// cross point on the left side
							// p点的纬度值和p1经度值的差，乘以p1p2线段的斜率，加上p1点的纬度值。
							// 求出交点的纬度值。
						double xinters = (p.x - p1.x) * (p2.y - p1.y) / (p2.x - p1.x) + p1.y;// cross point of y

						// 如果交点的纬度值和P点的纬度值相差小于最小经度，则判定p点在线段上，
						// 那么就认为p点在多边形内
						if (Math.abs(p.y - xinters) < precision) {// overlies on a ray
							return boundOrVertex;
						}
						// 如果p点的纬度值小于交叉点的纬度值，则记一次相交。
						if (p.y < xinters) {// before ray
							++intersectCount;
						}
					}
				}
			} else {// special case when ray is crossing through the vertex
					// 如果p点引出的射线和p1或者p2点相交
				if (p.x == p2.x && p.y <= p2.y) {// p crossing over p2
					Point2D.Double p3 = pts.get((i + 1) % N); // next vertex
					if (p.x >= Math.min(p1.x, p3.x) && p.x <= Math.max(p1.x, p3.x)) {// p.x lies between p1.x & p3.x
						// 如果p点的经度在点p3和p1的经度之间，则和p2点相交一次
						++intersectCount;
					} else {
						// 如果p点的经度不在p3和p1的经度之间，则和p2点相交两次
						intersectCount += 2;
					}
				}
			}
			// 检查下一点
			p1 = p2;// next ray left point
		}

		if (intersectCount % 2 == 0) {// 偶数在多边形外
			return false;
		} else { // 奇数在多边形内
			return true;
		}

	}

}
